home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / tests / pdevtest / server.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-01  |  16.2 KB  |  614 lines

  1. /* 
  2.  * server.c --
  3.  *
  4.  *    The server part of some multi-program synchronization primatives.
  5.  *    The routines here control N client programs.  This just means
  6.  *    telling them all to start, and hearing back from them when they're done.
  7.  *
  8.  * Copyright 1986 Regents of the University of California
  9.  * All rights reserved.
  10.  */
  11.  
  12. #ifndef lint
  13. static char rcsid[] = "$Header: /sprite/src/tests/pdevtest/RCS/server.c,v 1.3 88/08/26 17:43:37 brent Exp Locker: brent $ SPRITE (Berkeley)";
  14. #endif not lint
  15.  
  16.  
  17. #include <sprite.h>
  18. #include <status.h>
  19. #include <sys/file.h>
  20. #include <errno.h>
  21. #include <fs.h>
  22. #include <dev/pdev.h>
  23. #include <stdio.h>
  24. #include <time.h>
  25. #include <sys.h>
  26. #include <bit.h>
  27. #include "pdevInt.h"
  28.  
  29. char *pdev="./pdev";
  30.  
  31. extern Boolean writeBehind;
  32. extern int delay;
  33.  
  34. typedef int  (*IntProc)();
  35.  
  36. typedef struct ServerState {
  37.     int cntlStream;    /* Control stream to find out new clientStream's */
  38.     int numClients;
  39.     int *clientStream;    /* Array of client streams */
  40.     int maxStreamID;
  41.     Address *request;    /* Array of client request buffers */
  42.     char *clientState;    /* Array of client state words */
  43.     int *selectMask;
  44.     int selectMaskBytes;
  45.     IntProc opTable[7];    /* Operation switch table */
  46. } ServerState;
  47.  
  48. #define REPLY_BUF_SIZE        (16 * 1024)
  49. #define REQUEST_BUF_SIZE    (REPLY_BUF_SIZE + sizeof(Pdev_Request))
  50. #define CLIENT_OPENED    0x1
  51. #define CLIENT_STARTED    0x2
  52. #define CLIENT_FINISHED    0x4
  53.  
  54. /*
  55.  * Need the select flag to know if we should block the client.
  56.  */
  57. Boolean blocked = FALSE;
  58.  
  59. /*
  60.  * Forward Declarations
  61.  */
  62. ReturnStatus NullProc();
  63. ReturnStatus ServeOpen();
  64. ReturnStatus ServeRead();
  65. ReturnStatus ServeWrite();
  66. ReturnStatus ServeIOControl();
  67. int ServeRequest();
  68.  
  69.  
  70. /*
  71.  *----------------------------------------------------------------------
  72.  *
  73.  * ServerSetup --
  74.  *
  75.  *    Establish contact with N clients.  A pseudo device is opened
  76.  *    and we are declared its "master", or "server".  After this
  77.  *    other processes can open the pseudo device and we'll get a private
  78.  *    stream back that we use for requests from that process.
  79.  *
  80.  * Results:
  81.  *    A pointer to state about the clients needed by ServerStart and
  82.  *    ServerWait.
  83.  *
  84.  * Side effects:
  85.  *    Opens the pseudo device as the server and waits for numClients
  86.  *    opens by client processes.
  87.  *    This exits (kills the process) upon error.
  88.  *
  89.  *----------------------------------------------------------------------
  90.  */
  91.  
  92. void
  93. ServerSetup(numClients, dataPtr)
  94.     int numClients;
  95.     ClientData *dataPtr;
  96. {
  97.     ServerState *statePtr;
  98.     int client;
  99.     int len;
  100.     int amountRead;
  101.     ReturnStatus status;
  102.     Pdev_Notify notify;
  103.     Pdev_SetBufArgs setBuf;
  104.     int streamID;
  105.     int maxStreamID;
  106.  
  107.     statePtr = (ServerState *)malloc(sizeof(ServerState));
  108.     statePtr->clientStream = (int *)malloc(numClients * sizeof(int));
  109.     statePtr->clientState = (char *)malloc(numClients);
  110.     statePtr->request = (Address *)malloc(numClients * sizeof(Address));
  111.     statePtr->numClients = numClients;
  112.  
  113.     statePtr->opTable[(int)PDEV_OPEN] = ServeOpen;
  114.     statePtr->opTable[(int)PDEV_CLOSE] = NullProc;
  115.     statePtr->opTable[(int)PDEV_READ] = ServeRead;
  116.     statePtr->opTable[(int)PDEV_WRITE] = ServeWrite;
  117.     statePtr->opTable[(int)PDEV_IOCTL] = ServeIOControl;
  118.  
  119.     /*
  120.      * Open the pseudo device.
  121.      */
  122.     statePtr->cntlStream = open(pdev, O_CREAT | O_RDONLY | O_MASTER, 0666);
  123.     if (statePtr->cntlStream < 0) {
  124.     perror("Error opening pseudo device as master");
  125.     exit(errno);
  126.     }
  127.     maxStreamID = 0;
  128.     for (client=0 ; client<numClients ; client++) {
  129.     /*
  130.      * Read on our control stream (the one we just opened) messages
  131.      * that contain new streamIDs.  These are for private streams
  132.      * back to the client process..
  133.      */
  134.     amountRead = read(statePtr->cntlStream, (Address)¬ify, sizeof(notify));
  135.     if (amountRead < 0) {
  136.         perror("Error reading control stream");
  137.         exit(errno);
  138.     } else if (amountRead != sizeof(notify)) {
  139.         fprintf(stderr,
  140.         "Warning, short read (%d) on control stream\n", amountRead);
  141.     }
  142.     streamID = notify.newStreamID;
  143.     if (streamID > statePtr->maxStreamID) {
  144.         statePtr->maxStreamID = streamID;
  145.     }
  146.     /*
  147.      * Tell the kernel where the request buffer is.
  148.      */
  149.     statePtr->request[client] = (Address)malloc(REQUEST_BUF_SIZE);
  150.     setBuf.requestBufAddr = statePtr->request[client];
  151.     setBuf.requestBufSize = REQUEST_BUF_SIZE;
  152.     setBuf.readBufAddr = (Address)NULL;
  153.     setBuf.readBufSize = 0;
  154.     Fs_IOControl(streamID, IOC_PDEV_SET_BUF,
  155.             sizeof(Pdev_SetBufArgs), (Address)&setBuf, 0, NULL);
  156.     /*
  157.      * Set(Unset) write-behind by the client.
  158.      */
  159.     Fs_IOControl(streamID, IOC_PDEV_WRITE_BEHIND,
  160.             sizeof(int), (Address)&writeBehind, 0, NULL);
  161.     statePtr->clientStream[client] = streamID;
  162.     statePtr->clientState[client] = CLIENT_OPENED;
  163.     fprintf(stderr, "Got client on stream %d\n",streamID);
  164.     ServeRequest(statePtr->clientStream[client],
  165.              statePtr->request[client],
  166.              statePtr->opTable);
  167.     }
  168.     /*
  169.      * Now that we know the largest stream ID used for a client stream
  170.      * we can allocate and initialize the select mask for the streams.
  171.      */
  172.     statePtr->selectMaskBytes = Bit_NumBytes(statePtr->maxStreamID);
  173.     statePtr->selectMask = (int *)malloc(statePtr->selectMaskBytes);
  174.     bzero((Address)statePtr->selectMask, statePtr->selectMaskBytes);
  175.     for (client=0 ; client < numClients ; client++) {
  176.     Bit_Set(statePtr->clientStream[client], statePtr->selectMask);
  177.     }
  178.     *dataPtr = (ClientData)statePtr;
  179. }
  180.  
  181. /*
  182.  *----------------------------------------------------------------------
  183.  *
  184.  * ServeRequest --
  185.  *
  186.  *    The top level service routine that reads client requests
  187.  *    and branches out to a handler for the request.  This takes
  188.  *    care of error conditions and allocating space for the
  189.  *    request and the reply parameters.
  190.  *
  191.  * Results:
  192.  *    None
  193.  *
  194.  * Side effects:
  195.  *    The server side of the pseudo-device protocol.
  196.  *
  197.  *----------------------------------------------------------------------
  198.  */
  199.  
  200. int
  201. ServeRequest(clientStreamID, myRequestBuf, opTable)
  202.     int clientStreamID;
  203.     Address myRequestBuf;
  204.     IntProc *opTable;
  205. {
  206.     register ReturnStatus status;
  207.     register Pdev_Request *requestPtr;
  208.     Pdev_Reply reply;
  209.     Pdev_BufPtrs bufPtrs;
  210.     register int operation;
  211.     int numBytes;
  212.     char replyBuf[REPLY_BUF_SIZE];
  213.     register char *requestData;
  214.     register Address requestBuf;
  215.     register int i;
  216.  
  217.     /*
  218.      * Read the current pointers for the request buffer.
  219.      */
  220.  
  221.     numBytes = read(clientStreamID, (Address) &bufPtrs, sizeof(Pdev_BufPtrs));
  222.     if (numBytes != sizeof(Pdev_BufPtrs)) {
  223.     panic("%s; errno %d, count %d",
  224.         "ServeRequest had trouble reading request buffer pointers",
  225.         errno, numBytes);
  226.     }
  227.     if (bufPtrs.magic != PDEV_BUF_PTR_MAGIC) {
  228.     panic("%s: %d", "ServeRequest got bad pointer magic number",
  229.         bufPtrs.magic);
  230.     }
  231.     /*
  232.      * While there are still requests in the buffer, service them.
  233.      */
  234.     requestBuf = bufPtrs.requestAddr;
  235.     while (bufPtrs.requestFirstByte < bufPtrs.requestLastByte) {
  236.     requestPtr = (Pdev_Request *)&requestBuf[bufPtrs.requestFirstByte];
  237.     if (requestPtr->hdr.magic != PDEV_REQUEST_MAGIC) {
  238.         panic("ServeRequest, bad request magic # 0x%x\n",
  239.                 requestPtr->hdr.magic);
  240.     }
  241.     requestData = (Address)((int)requestPtr + sizeof(Pdev_Request));
  242.  
  243.     /*
  244.      * Switch out the to the handler for the pdev operation.
  245.      */
  246.     operation = requestPtr->hdr.operation;
  247.     status = (*opTable[(int)operation])(clientStreamID,
  248.         requestPtr, requestData, replyBuf, &reply.selectBits);
  249.  
  250.     if (delay > 0) {
  251.         for (i=delay<<1 ; i>0 ; i--) ;
  252.     }
  253.  
  254.     if (operation != PDEV_WRITE_ASYNC) {
  255.         /*
  256.          * Set up the reply and tell the kernel about it.
  257.          */
  258.     
  259.         reply.magic = PDEV_REPLY_MAGIC;
  260.         reply.status = SUCCESS;
  261.         reply.replySize = requestPtr->hdr.replySize;
  262.         reply.replyBuf = replyBuf;
  263.         status = Fs_IOControl(clientStreamID, IOC_PDEV_REPLY,
  264.                     sizeof(Pdev_Reply),
  265.                     (Address) &reply, 0, NULL);
  266.         if (status != SUCCESS) {
  267.         panic("%s; status \"%s\"",
  268.             "ServeRequest couldn't send reply",
  269.             Stat_GetMsg(status));
  270.         }
  271.     }
  272.     bufPtrs.requestFirstByte += requestPtr->hdr.messageSize;
  273.     }
  274.     Fs_IOControl(clientStreamID, IOC_PDEV_SET_PTRS,
  275.             sizeof(Pdev_BufPtrs), (Address)&bufPtrs,
  276.             0, NULL);
  277.     return(operation);
  278. }
  279.  
  280. /*
  281.  *----------------------------------------------------------------------
  282.  *
  283.  * Serve --
  284.  *
  285.  *    Listen for requests from client's, returning after all clients
  286.  *    have closed their streams.
  287.  *
  288.  * Results:
  289.  *    None
  290.  *
  291.  * Side effects:
  292.  *    Handle all requests by clients.
  293.  *
  294.  *----------------------------------------------------------------------
  295.  */
  296.  
  297. void
  298. Serve(data)
  299.     ClientData data;
  300. {
  301.     ServerState *statePtr;
  302.     int client;
  303.     ReturnStatus status;
  304.     int *selectMask;
  305.     int numFinishedClients;
  306.     int numReady;
  307.     int operation;
  308.  
  309.     statePtr = (ServerState *)data;
  310.     selectMask = (int *)malloc(statePtr->selectMaskBytes);
  311.     numFinishedClients = 0;
  312.     do {
  313.     bcopy((Address)statePtr->selectMask, (Address)selectMask,
  314.         statePtr->selectMaskBytes);
  315.     status = Fs_Select(statePtr->numClients, NULL, selectMask,
  316.                 NULL, NULL, &numReady);
  317.     for (client=0 ; client < statePtr->numClients ; client++) {
  318.         /*
  319.          * Look for the each client's bit in the select mask and read the
  320.          * corresponding stream for its initial request.
  321.          */
  322.         if (Bit_IsSet(statePtr->clientStream[client], selectMask)) {
  323.         /*
  324.          * Handle the client's request.  If it's a close
  325.          * then clear the client's bit from the select mask so
  326.          * don't bother checking it again.
  327.          */
  328.         operation = ServeRequest(statePtr->clientStream[client],
  329.                  statePtr->request[client],
  330.                  statePtr->opTable);
  331.         if (operation == PDEV_CLOSE ||
  332.             operation == -1) {
  333.             fprintf(stderr, "Client %d %s...", client,
  334.             (operation == PDEV_CLOSE) ? "closed" : "error" );
  335.             numFinishedClients++;
  336.             statePtr->clientState[client] |= CLIENT_FINISHED;
  337.             Bit_Clear(statePtr->clientStream[client],
  338.                 statePtr->selectMask);
  339.         } else if ((operation == PDEV_READ) && selectP) {
  340.             /*
  341.              * If the select flag is set, then we must
  342.              * remember to simulate input for the client
  343.              * every so often.  This tests regular blocking
  344.              * reads, and selects by the client.  This goes
  345.              * with the fact that we only return FS_WRITABLE
  346.              * if the select flag is set.
  347.              */
  348.             Time time;
  349.             int selectBits;
  350.             time.seconds = 0;
  351.             time.microseconds = 400;
  352.             Sync_WaitTime(time);
  353.             printf("Waking up client\n");
  354.             selectBits = FS_READABLE|FS_WRITABLE;
  355.             Fs_IOControl(statePtr->clientStream[client],
  356.                 IOC_PDEV_READY, sizeof(int), &selectBits,
  357.                 0, NULL);
  358.         }
  359.         }
  360.     }
  361.     } while (numFinishedClients < statePtr->numClients);
  362.     fprintf(stderr, "\n");
  363. }
  364.  
  365. /*
  366.  *----------------------------------------------------------------------
  367.  *
  368.  * ServeOne --
  369.  *
  370.  *    A service loop for one client.  More bare-bones test used
  371.  *    for timing.
  372.  *
  373.  * Results:
  374.  *    None
  375.  *
  376.  * Side effects:
  377.  *    Handle all requests one client.
  378.  *
  379.  *----------------------------------------------------------------------
  380.  */
  381.  
  382. void
  383. ServeOne(data)
  384.     ClientData data;
  385. {
  386.     register ServerState *statePtr;
  387.     register int client;
  388.     ReturnStatus status;
  389.     int *selectMask;
  390.     int numFinishedClients;
  391.     int numReady;
  392.     int operation;
  393.  
  394.     statePtr = (ServerState *)data;
  395.     client = 0;
  396.     do {
  397.     operation = ServeRequest(statePtr->clientStream[client],
  398.              statePtr->request[client],
  399.              statePtr->opTable);
  400.     if (operation == PDEV_CLOSE ||
  401.         operation == -1) {
  402.         fprintf(stderr, "Client %d %s...", client,
  403.         (operation == PDEV_CLOSE) ? "closed" : "error" );
  404.         break;
  405.     } else if ((operation == PDEV_READ) && selectP) {
  406.         /*
  407.          * If the select flag is set, then we must
  408.          * remember to simulate input for the client
  409.          * every so often.  This tests regular blocking
  410.          * reads, and selects by the client.  This goes
  411.          * with the fact that we only return FS_WRITABLE
  412.          * if the select flag is set.
  413.          */
  414.         Time time;
  415.         int selectBits;
  416.         time.seconds = 0;
  417.         time.microseconds = 400;
  418.         Sync_WaitTime(time);
  419.         printf("Waking up client\n");
  420.         selectBits = FS_READABLE|FS_WRITABLE;
  421.         Fs_IOControl(statePtr->clientStream[client],
  422.             IOC_PDEV_READY, sizeof(int), &selectBits,
  423.             0, NULL);
  424.     }
  425.     } while (1);
  426.     fprintf(stderr, "\n");
  427. }
  428.  
  429. /*
  430.  *----------------------------------------------------------------------
  431.  *
  432.  * NullProc --
  433.  *
  434.  *    The do-nothing service procedure.
  435.  *
  436.  * Results:
  437.  *    SUCCESS
  438.  *
  439.  * Side effects:
  440.  *    Zeroes out the reply buffer.
  441.  *
  442.  *----------------------------------------------------------------------
  443.  */
  444.  
  445. ReturnStatus
  446. NullProc(streamID, requestPtr, requestBuf, replyBuf, selectBitsPtr)
  447.     int streamID;
  448.     Pdev_Request *requestPtr;
  449.     Address requestBuf;
  450.     Address replyBuf;
  451.     int *selectBitsPtr;
  452. {
  453.     if (requestPtr->hdr.replySize > 0) {
  454.     bzero(replyBuf, requestPtr->hdr.replySize);
  455.     }
  456.     return(SUCCESS);
  457. }
  458.  
  459. /*
  460.  *----------------------------------------------------------------------
  461.  *
  462.  * ServeOpen --
  463.  *
  464.  *    React to an Open request.  This initializes the
  465.  *    select state to both readable and writable.
  466.  *
  467.  * Results:
  468.  *    SUCCESS
  469.  *
  470.  * Side effects:
  471.  *    Print statement.
  472.  *
  473.  *----------------------------------------------------------------------
  474.  */
  475.  
  476. ReturnStatus
  477. ServeOpen(streamID, requestPtr, requestBuf, replyBuf, selectBitsPtr)
  478.     int streamID;
  479.     Pdev_Request *requestPtr;
  480.     Address requestBuf;
  481.     Address replyBuf;
  482.     int *selectBitsPtr;
  483. {
  484.     fprintf(stderr, "Open request, streamID %d\n", streamID);
  485.     *selectBitsPtr = FS_READABLE | FS_WRITABLE;
  486.     return(SUCCESS);
  487. }
  488.  
  489. /*
  490.  *----------------------------------------------------------------------
  491.  *
  492.  * ServeRead --
  493.  *
  494.  *    Return data for a read request.  This plays a game with the
  495.  *    client if the select flag (-s) is set:  every other read
  496.  *    gets blocked in order to test IOC_PDEV_READY.
  497.  *
  498.  * Results:
  499.  *    SUCCESS
  500.  *
  501.  * Side effects:
  502.  *    Zeroes out the reply buffer.
  503.  *
  504.  *----------------------------------------------------------------------
  505.  */
  506.  
  507. ReturnStatus
  508. ServeRead(streamID, requestPtr, requestBuf, replyBuf, selectBitsPtr)
  509.     int streamID;
  510.     Pdev_Request *requestPtr;
  511.     Address requestBuf;
  512.     Address replyBuf;
  513.     int *selectBitsPtr;
  514. {
  515.     if (selectP && !blocked) {
  516.     blocked = TRUE;
  517.     *selectBitsPtr = FS_WRITABLE;
  518.     return(FS_WOULD_BLOCK);
  519.     } else {
  520.     if (requestPtr->hdr.replySize > 0) {
  521.         bzero(replyBuf, requestPtr->hdr.replySize);
  522.         replyBuf[0] = 'z';
  523.     }
  524.     blocked = FALSE;
  525.     if (! selectP) {
  526.         *selectBitsPtr = FS_WRITABLE | FS_READABLE;
  527.     } else {
  528.         *selectBitsPtr = FS_WRITABLE;
  529.     }
  530.     return(SUCCESS);
  531.     }
  532. }
  533.  
  534. /*
  535.  *----------------------------------------------------------------------
  536.  *
  537.  * ServeWrite --
  538.  *
  539.  *    Handle a write request.
  540.  *
  541.  * Results:
  542.  *    SUCCESS
  543.  *
  544.  * Side effects:
  545.  *    Sets up the select bits.
  546.  *
  547.  *----------------------------------------------------------------------
  548.  */
  549.  
  550. ReturnStatus
  551. ServeWrite(streamID, requestPtr, requestBuf, replyBuf, selectBitsPtr)
  552.     int streamID;
  553.     Pdev_Request *requestPtr;
  554.     Address requestBuf;
  555.     Address replyBuf;
  556.     int *selectBitsPtr;
  557. {
  558.     *selectBitsPtr = FS_WRITABLE;
  559.     if (! selectP) {
  560.     *selectBitsPtr |= FS_READABLE;
  561.     }
  562.     requestPtr->hdr.replySize = sizeof(int);
  563.     *(int *)replyBuf = requestPtr->hdr.requestSize;
  564.     return(SUCCESS);
  565. }
  566.  
  567. /*
  568.  *----------------------------------------------------------------------
  569.  *
  570.  * ServeIOControl --
  571.  *
  572.  *    Handle an IOControl.  This acts like an echo now.
  573.  *
  574.  * Results:
  575.  *    SUCCESS
  576.  *
  577.  * Side effects:
  578.  *    Copies the request buffer to the reply buffer.
  579.  *
  580.  *----------------------------------------------------------------------
  581.  */
  582.  
  583. ReturnStatus
  584. ServeIOControl(streamID, requestPtr, requestBuf, replyBuf, selectBitsPtr)
  585.     int streamID;
  586.     Pdev_Request *requestPtr;
  587.     Address requestBuf;
  588.     Address replyBuf;
  589.     int *selectBitsPtr;
  590. {
  591.     switch (requestPtr->param.ioctl.command) {
  592.     case IOC_PDEV_SET_BUF: {
  593.         /*
  594.          * Let the client trigger our test of the mid-flight
  595.          * setbuf call.
  596.          */
  597.         Pdev_SetBufArgs setBuf;
  598.  
  599.         setBuf.requestBufAddr = (Address)malloc(REQUEST_BUF_SIZE);
  600.         setBuf.requestBufSize = REQUEST_BUF_SIZE;
  601.         setBuf.readBufAddr = (Address)NULL;
  602.         setBuf.readBufSize = 0;
  603.         Fs_IOControl(streamID, IOC_PDEV_SET_BUF,
  604.                 sizeof(Pdev_SetBufArgs), (Address)&setBuf, 0, NULL);
  605.     
  606.     }
  607.     }
  608.     *selectBitsPtr = FS_WRITABLE;
  609.     if (! selectP) {
  610.     *selectBitsPtr |= FS_READABLE;
  611.     }
  612.     return(SUCCESS);
  613. }
  614.